 package org.beetl.sql.ext.jpa.mapper.builder;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.beetl.sql.clazz.kit.BeetlSQLException;
import org.beetl.sql.clazz.kit.PropertiesKit;
import org.beetl.sql.clazz.kit.StringKit;
import org.beetl.sql.ext.jpa.mapper.ready.JpaDataPageSqlReadyMI;
import org.beetl.sql.ext.jpa.mapper.template.JpaDataPageTemplateMI;
import org.beetl.sql.mapper.MapperInvoke;
import org.beetl.sql.mapper.builder.MethodParam;
import org.beetl.sql.mapper.builder.MethodParamsHolder;
import org.beetl.sql.mapper.builder.ReturnTypeParser;
import org.beetl.sql.mapper.ready.SelectSqlReadyMI;
import org.beetl.sql.mapper.ready.UpdateSqlReadyMI;
import org.beetl.sql.mapper.springdata.SpringDataBuilder;
import org.beetl.sql.mapper.template.SelectTemplateMI;
import org.beetl.sql.mapper.template.UpdateTemplateMI;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;

public class JpaDataBuilder extends SpringDataBuilder{
	private final Pattern POSITION_PARAMETER_TEMPLATE = Pattern.compile("\\?(\\d+)");// 问号+序号 方式
	private final Pattern NAMED_PARAMETER_TEMPLATE = Pattern.compile(":([a-zA-Z0-9_]+)");// 冒号+字符串 方式
//	private final String POSITION_TEMPLATE = "?%s";
//	private final String NAMED_TEMPLATE = ":%s";
	
	
	private final int preferredSqlLen;
	
	private final String DELIMITER_PLACEHOLDER_START;// 占位符开始符号
	private final String DELIMITER_PLACEHOLDER_END;// 占位符结束符号
	
	private Set<String> __if = new HashSet<>();
	
	public JpaDataBuilder() {
		this.preferredSqlLen = PropertiesKit.getInstance().getIntValue("MAPPER_SQL_MAX_LENGTH", "-1");
		this.DELIMITER_PLACEHOLDER_START = PropertiesKit.getInstance().getValue("DELIMITER_PLACEHOLDER_START");
		this.DELIMITER_PLACEHOLDER_END = PropertiesKit.getInstance().getValue("DELIMITER_PLACEHOLDER_END");
	}

	@Override
	public MapperInvoke parse(Class entity, Method m) {
//		Annotation noRepository =  entity.getAnnotation(NoRepositoryBean.class);
//		if(noRepository!=null) {
//			throw new BeetlSQLException(BeetlSQLException.MAPPER_ERROR, "注解@NoRepositoryBean不能初始化");
//		}
//		Annotation repository = entity.getAnnotation(Repository.class);
//		if(repository==null) {
//			throw new BeetlSQLException(BeetlSQLException.MAPPER_ERROR, "无注解@Repository");
//		}
		Query queryAnnotation = m.getAnnotation(Query.class);
		if (queryAnnotation != null) {
			MapperInvoke invoke = parseSqlMethod(queryAnnotation,entity,m);
			return invoke;
		}
		return super.parse(entity,m);
	}
	
	private MapperInvoke parseSqlMethod(Query sqlAnnotation,Class entity,Method method) {
		boolean naQuery = sqlAnnotation.nativeQuery(); //TODO 暂时仅支持非jsql的
		if(!naQuery) {
			throw new UnsupportedOperationException("抱歉，暂时不支持jpa或hibernate 方式的sql!");
		}
		String jdbcSql = sqlAnnotation.value();
		checkSqlLength(jdbcSql,method);
		
		Annotation action = getSqlType(method);
		
		ReturnTypeParser returnTypeParser = new ReturnTypeParser(method,entity);
//		if (returnTypeParser.isPageResult()) {
//			Class targetRetType = returnTypeParser.getPageResultType();
//			if(targetRetType.equals(Object.class) || Object.class.isAssignableFrom(targetRetType)) {
//			}
//		}
		//参数说明
		JpaDataParameterParser parameterParser = new JpaDataParameterParser(method);
		MethodParamsHolder paramsHolder = parameterParser.getHolder();
//		List<MethodParam> paras =  paramsHolder.getParas();
		
		jdbcSql = getSql(jdbcSql, paramsHolder);//尽量hsql中的sql占位符转为beetlsql的template name方式占位符
		
//	    if(returnTypeParser.isCollection()) {
//	    	__if.add("col");//List,Set,Map
//	    }
//		if(paras !=null && paras.size() > 0) {
//			__if.add("paras");//拥有参数
//		}
//		if(paramsHolder.hasPageRequest()) {
//			__if.add("page_p");//拥有分页参数
//		}
//		if(returnTypeParser.isPageResult()) {
//			__if.add("page_r");//需要返回分页结果
//		}
		
		//TODO 暂时不支持分页 //TODO 怎么优化
		if (action == null) {//查询操作
			return select(jdbcSql,paramsHolder,returnTypeParser,sqlAnnotation);
		} else if (action instanceof Modifying) {
			return update(jdbcSql,paramsHolder);
		} 
		throw new UnsupportedOperationException("啥？非法操作！");
	}
	
	//不支持返回值
	private MapperInvoke update(String sql, MethodParamsHolder holder) {
		if(__if.contains("templ")) {
			return new UpdateTemplateMI(sql, holder);
		}
		return new UpdateSqlReadyMI(sql);
	}
	
	//分页支持仍有点问题
	private  MapperInvoke select(String sql, MethodParamsHolder holder,ReturnTypeParser returnTypeParser,Query sqlAnnotation) {
		if (holder.hasPageRequest()) {
			String countSql = sqlAnnotation.countQuery();
			if(StringKit.isBlank(countSql)) {
				throw new IllegalArgumentException("Query Page countQuery must not be null");
			}
			checkSqlLength(countSql,null);
			countSql = getSql(countSql, holder);
			if (returnTypeParser.isPageResult()) {
				Class targetRetType = returnTypeParser.getPageResultType();
				if(__if.contains("templ")) {
					return new JpaDataPageTemplateMI(sql, returnTypeParser, true, holder,countSql);
				}
				return new JpaDataPageSqlReadyMI(sql, returnTypeParser, true, holder,countSql);
			} else {
				Class targetRetType = returnTypeParser.getPageResultType();
				if(__if.contains("templ")) {
					return new JpaDataPageTemplateMI(sql, returnTypeParser, false, holder,countSql);
				}
				return new JpaDataPageSqlReadyMI(sql, returnTypeParser, false, holder,countSql);
			}
		} else {
			if (returnTypeParser.isCollection()) {
				Class targetRetType = returnTypeParser.getCollectionType();
				if(__if.contains("templ")) {
					return new SelectTemplateMI(sql, targetRetType, holder, false);
				}
				return new SelectSqlReadyMI(sql, targetRetType, false);
			} else {
				if(__if.contains("templ")) {
					return new SelectTemplateMI(sql, returnTypeParser.getType(), holder, true);
				}
				return new SelectSqlReadyMI(sql, returnTypeParser.getType(), true);
			}
		}
	}
	
	private String getSql(String jdbcSql,MethodParamsHolder paramsHolder) {
		Matcher matcher = POSITION_PARAMETER_TEMPLATE.matcher(jdbcSql);
		List<MethodParam> paras =  paramsHolder.getParas();
		
		Map<Integer,String> _im = new HashMap<>();
		Map<String,String> _nm = new HashMap<>();
		for(MethodParam m:paras) {
			String e = Matcher.quoteReplacement(appendVar(m.getName()));
			_im.put(m.getIndex(), e);
			_nm.put(m.getName(), e);
		}
		StringBuffer sb = new StringBuffer();
		boolean flag = false;
		while(matcher.find()) {
			flag = true;
			int parameterIndex = Integer.parseInt(matcher.group(1));
			if(parameterIndex > 0 && parameterIndex < paras.size()+1) {
			  String pn = _im.get(parameterIndex);
			  matcher.appendReplacement(sb, pn);
			} else {
                throw new IllegalArgumentException("Invalid parameter index: " + parameterIndex);
            }
		}
		if(flag) {
			matcher.appendTail(sb);
			__if.add("templ"); // 使用template模板进行解析
			return sb.toString();
		}
		
		matcher = NAMED_PARAMETER_TEMPLATE.matcher(jdbcSql);
		while(matcher.find()) {
			flag = true;
			String placeholder = matcher.group(1);
			String pn = _nm.get(placeholder);
			matcher.appendReplacement(sb, pn);
		}
		if(flag) {
			matcher.appendTail(sb);
			__if.add("templ"); // 使用template模板进行解析
			return sb.toString();
		}
		return jdbcSql;
	}
	
	private void checkSqlLength(String sql,Method method) {
		if (preferredSqlLen == -1) {
			return;
		}
		if (sql.length() > preferredSqlLen) {
			throw new BeetlSQLException(BeetlSQLException.MAPPER_SQL_LIMIT,
					"期望Mapper方法 " + method + " 的SQL最大长度是 " + preferredSqlLen + " 实际是 " + sql.length());
		}
	}
	
	private Annotation getSqlType(Method method) {
		Modifying update = method.getAnnotation(Modifying.class);
		if (update != null) {
//			__if.add("upd");//update or delete
			return update;
		}
//		__if.add("sel");//select
		return null;
	}
	
	private String appendVar(String express) {
        return DELIMITER_PLACEHOLDER_START + express + DELIMITER_PLACEHOLDER_END + " ";
    }

}
